#ifndef ___procesar_comandos

#define ___procesar_comandos 1

#include "pd_pcoms.c"
#include "pd_pcad.c"
#include <stdlib.h>
#include <stdio.h>

comando_t obtenerComando(void);
char * obtenerLinea(void);
comando_t procesarComando(char *);
comando_t procesarAbrir(char *);
comando_t procesarUsarDisco(char *);
comando_t procesarUsarConexion(char *);
comando_t procesarLeer(char *);
comando_t procesarEscribir(char *);
comando_t procesarProbar(char *);
sectores_t procesarSectores(char **);
comando_t procesarDatosEscritura(comando_t, char *);
sectores_t procesarListaSectores(char **);
comando_t procesarDatosCadenaEscritura(comando_t, int);

comando_t obtenerComando (void) {
  putchar('>');
  char * linea = obtenerLinea();
  comando_t datos = procesarComando(linea);
  free(linea);
  return datos;
}

char * obtenerLinea (void) {
  char * linea = malloc(1);
  int caracteres = 0;
  int caracter;
  for (caracter = getchar(); (caracter != '\n') && (caracter != EOF); caracter = getchar()) {
    linea = realloc(linea, caracteres + 2);
    linea[caracteres] = caracter;
    caracteres ++;
  }
  linea[caracteres] = 0;
  return linea;
}

comando_t procesarComando (char * comando) {
  char * cmd = comando;
  comando_t resultado;
  signed long long primerToken = siguienteToken(&cmd);
  switch (primerToken) {
  case TOK_ABRIR:
    return procesarAbrir(cmd);
  case TOK_LEER:
    return procesarLeer(cmd);
  case TOK_ESCRIBIR:
    return procesarEscribir(cmd);
  case TOK_PROBAR:
    return procesarProbar(cmd);
  case TOK_CERRAR:
    resultado.tipo = cmd ? 0 : 2;
    return resultado;
  case TOK_USAR:
    if (!cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    primerToken = siguienteToken(&cmd);
    if (primerToken == TOK_DISCO) return procesarUsarDisco(cmd);
    else if (primerToken == TOK_CONEXION) return procesarUsarConexion(cmd);
    else {
      resultado.tipo = 0;
      return resultado;
    }
  default:
    resultado.tipo = 0;
    return resultado;
  }
}

comando_t procesarAbrir(char * comando) {
  char * cmd = comando;
  comando_t resultado;
  resultado.tipo = 1;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  signed long long token;
  token = siguienteToken(&cmd);
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  if (token == TOK_CONEXION)
    resultado.datos.abrir.cantidad = 1;
  else if (token > 0) {
    resultado.datos.abrir.cantidad = token;
    token = siguienteToken(&cmd);
    if (token != TOK_CONEXIONES) {
      resultado.tipo = 0;
      return resultado;
    }
  } else {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_EN) {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_IP) {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if ((token < 0) || (token > 255)){
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.abrir.elem0 = token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if ((token < 0) || (token > 255)){
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.abrir.elem1 = token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if ((token < 0) || (token > 255)){
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.abrir.elem2 = token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if ((token < 0) || (token > 255)){
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.abrir.elem3 = token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_PUERTO) {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if ((token < 1) || (token > 65535)){
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.abrir.puerto = token;
  if (cmd) resultado.tipo = 0;
  return resultado;
}

comando_t procesarUsarDisco(char * comando) {
  char * cmd = comando;
  comando_t resultado;
  resultado.tipo = 3;
  signed long long token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_DE) {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token <= 0) {
    resultado.tipo = 0;
    return resultado;
  }
  resultado.datos.sectoresDisco = token;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_SECTORES) {
    resultado.tipo = 0;
    return resultado;
  }
  if (cmd) resultado.tipo = 0;
  return resultado;
}

comando_t procesarUsarConexion(char * comando) {
  char * cmd = comando;
  signed long long token;
  comando_t resultado;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  resultado.tipo = 4;
  token = siguienteToken(&cmd);
  if (cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  if (token == TOK_ALEATORIA) resultado.datos.conexion = -1;
  else if (token > 0) resultado.datos.conexion = token;
  else resultado.tipo = 0;
  return resultado;
}

comando_t procesarLeer(char * comando) {
  char * cmd = comando;
  comando_t resultado;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  resultado.tipo = 5;
  sectores_t sectores = procesarSectores(&cmd);
  if (sectores.tipo && !cmd) resultado.datos.sectoresLeer = sectores; else resultado.tipo = 0;
  return resultado;
}

comando_t procesarEscribir(char * comando) {
  char * cmd = comando;
  signed long long token;
  sectores_t sectores;
  comando_t resultado;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  resultado.tipo = 6;
  sectores = procesarSectores(&cmd);
  if (sectores.tipo)
    resultado.datos.escribir.sectores = sectores;
  else {
    resultado.tipo = 0;
    return resultado;
  }
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&cmd);
  if (token != TOK_CON) {
    resultado.tipo = 0;
    return resultado;
  }
  return procesarDatosEscritura(resultado, cmd);
}

comando_t procesarProbar(char * comando) {
  signed long long token;
  comando_t resultado;
  resultado.tipo = 7;
  char * datos = comando;
  if (!datos) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(&datos);
  if (token == TOK_CONEXIONES) {
    if (!datos) resultado.datos.conexion = -1; else resultado.tipo = 0;
  } else if (token == TOK_CONEXION) {
    if (!datos) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(&datos);
    if ((token < 0) || datos) {
      resultado.tipo = 0;
      return resultado;
    }
    resultado.datos.conexion = token;
  } else resultado.tipo = 0;
  return resultado;
}

sectores_t procesarSectores (char ** comando) {
  signed long long token;
  sectores_t resultado;
  token = siguienteToken(comando);
  if (token == TOK_TODO)
    resultado.tipo = 5;
  else if (token == TOK_SECTOR) {
    resultado.tipo = 1;
    if (!(*comando)) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(comando);
    if (token == TOK_ALEATORIO) {
      resultado.tipo = 3;
      resultado.valores.cantidad = 1;
      return resultado;
    }
    if (token < 0) {
      resultado.tipo = 0;
      return resultado;
    }
    resultado.valores.sector = token;
  }
  else if (token == TOK_SECTORES)
    resultado = procesarListaSectores(comando);
  else if (token > 0) {
    if (!(*comando)) {
      resultado.tipo = 0;
      return resultado;
    }
    long cantSectores = token;
    token = siguienteToken(comando);
    if (token != TOK_SECTORES) {
      resultado.tipo = 0;
      return resultado;
    }
    if (!(*comando)) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(comando);
    if (token == TOK_ALEATORIOS) {
      resultado.tipo = 3;
      resultado.valores.cantidad = cantSectores;
    } else if (token == TOK_DESDE) {
      resultado.tipo = 2;
      if (!(*comando)) {
        resultado.tipo = 0;
        return resultado;
      }
      token = siguienteToken(comando);
      if (token < 0) {
        resultado.tipo = 0;
        return resultado;
      }
      resultado.valores.rango.inicio = token;
      resultado.valores.rango.fin = token + cantSectores - 1;
    } else if (token == TOK_HASTA) {
      resultado.tipo = 2;
      if (!(*comando)) {
        resultado.tipo = 0;
        return resultado;
      }
      token = siguienteToken(comando);
      if (token < (cantSectores - 1)) {
        resultado.tipo = 0;
        return resultado;
      }
      resultado.valores.rango.fin = token;
      resultado.valores.rango.inicio = token + 1 - cantSectores;
    } else 
      resultado.tipo = 0;
  } else
    resultado.tipo = 0;
  return resultado;
}

comando_t procesarDatosEscritura (comando_t comandoParcial, char * comando) {
  char * cmd = comando;
  comando_t resultado = comandoParcial;
  int posicion;
  if (!cmd) {
    resultado.tipo = 0;
    return resultado;
  }
  signed long long token;
  token = siguienteToken(&cmd);
  switch (token) {
  case TOK_DATOS:
    if (!cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(&cmd);
    if (cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    if (token == TOK_NULOS)
      for (posicion = 0; posicion < 512; posicion ++)
        resultado.datos.escribir.bytes[posicion] = 0;
    else if (token == TOK_ALEATORIOS)
      for (posicion = 0; posicion < 512; posicion ++)
        resultado.datos.escribir.bytes[posicion] = (char) rand();
    else
      resultado.tipo = 0;
    break;
  case TOK_CADENA:
    if (!cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(&cmd);
    int repeticiones;
    if (token == TOK_UNICA) {
      if (cmd) {
        resultado.tipo = 0;
        return resultado;
      }
      repeticiones = 1;
    } else if (token == TOK_REPETIDA) {
      if (cmd) {
        token = siguienteToken(&cmd);
        if (token <= 0) {
          resultado.tipo = 0;
          return resultado;
        }
        repeticiones = token;
        if (!cmd) {
          resultado.tipo = 0;
          return resultado;
        }
        token = siguienteToken(&cmd);
        if (cmd || (token != TOK_VECES)) {
          resultado.tipo = 0;
          return resultado;
        }
      } else
        repeticiones = 999;
    } else {
      resultado.tipo = 0;
      return resultado;
    }
    return procesarDatosCadenaEscritura(resultado, repeticiones);
  case TOK_LETRA:
    if (!cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(&cmd);
    if (cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    if ((token < -26) || (token > -1)) {
      resultado.tipo = 0;
      return resultado;
    }
    for (posicion = 0; posicion < 512; posicion ++)
      resultado.datos.escribir.bytes[posicion] = (char) (64 - token);
    break;
  case TOK_CARACTER:
    if (!cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(&cmd);
    if (cmd) {
      resultado.tipo = 0;
      return resultado;
    }
    if ((token < 0) || (token > 255)) {
      resultado.tipo = 0;
      return resultado;
    }
    for (posicion = 0; posicion < 512; posicion ++)
      resultado.datos.escribir.bytes[posicion] = (char) token;
    break;
  default:
    resultado.tipo = 0;
  }
  return resultado;
}

sectores_t procesarListaSectores (char ** comando) {
  signed long long token;
  sectores_t resultado;
  if (!(*comando)) {
    resultado.tipo = 0;
    return resultado;
  }
  token = siguienteToken(comando);
  if ((token < 0) || !(*comando)) {
    resultado.tipo = 0;
    return resultado;
  }
  long primerSector = token;
  token = siguienteToken(comando);
  if (token == TOK_A) {
    resultado.tipo = 2;
    resultado.valores.rango.inicio = primerSector;
    if (!(*comando)) {
      resultado.tipo = 0;
      return resultado;
    }
    token = siguienteToken(comando);
    if (token < 0) {
      resultado.tipo = 0;
      return resultado;
    }
    resultado.valores.rango.fin = token;
    return resultado;
  }
  int estado = 2;
  resultado.tipo = 4;
  resultado.valores.lista.cantidad = 1;
  resultado.valores.lista.numeros = malloc(sizeof(long));
  resultado.valores.lista.numeros[0] = primerSector;
  while (estado) {
    if (token == TOK_Y) {
      if (estado == 2) {
        estado = 1;
        token = siguienteToken(comando);
        continue;
      } else {
        free(resultado.valores.lista.numeros);
        resultado.tipo = 0;
        return resultado;
      }
    }
    if (token < 0) {
      free(resultado.valores.lista.numeros);
      resultado.tipo = 0;
      return resultado;
    }
    if (estado == 1) estado = 0;
    resultado.valores.lista.cantidad ++;
    resultado.valores.lista.numeros = realloc(resultado.valores.lista.numeros, sizeof(long) * resultado.valores.lista.cantidad);
    resultado.valores.lista.numeros[resultado.valores.lista.cantidad - 1] = token;
    if (estado) {
      if (!(*comando)) {
        free(resultado.valores.lista.numeros);
        resultado.tipo = 0;
        return resultado;
      }
      token = siguienteToken(comando);
    }
  }
  return resultado;
}

comando_t procesarDatosCadenaEscritura (comando_t comando, int repeticiones) {
  printf("Cadena: ");
  char * linea = obtenerLinea();
  if (!(*linea)) {
    free(linea);
    comando.tipo = 0;
    return comando;
  }
  int posicion;
  int posLinea = 0;
  for (posicion = 0; posicion < 512; posicion ++)
    if (repeticiones) {
      comando.datos.escribir.bytes[posicion] = linea[posLinea];
      posLinea ++;
      if (!linea[posLinea]) {
        posLinea = 0;
        repeticiones --;
      }
    } else
      comando.datos.escribir.bytes[posicion] = 0;
  return comando;
}

#endif